//
// Created by wxd on 2025/7/20.
// 坐标转化工具类
// Note：针对编译器的优化策略，尽量将除法转化为乘法
//

// note: 下面的坐标讨论仅限制在OpenGL框架在讨论
// NDC: [-1,1]^3  x水平方向：右侧为正方向；y竖直方向：上侧为正方向；z前后方向：不通风的graphic-api不同，针对OpenGL，-z朝屏幕内（右手系）
// Screen: [0, W] x [0, H] x [0, 1]: 原点在左上角，x的正方向为下，y的正方向为右, +z朝向屏幕内
// NDC: [-1,1]x[-1,1] -> [0,2]x[0,2] -> [0,1]x[0,1] -> [0,W]x[0,H]
// NDC的远近平面 近平面：z = -1 远平面：z = 1,
// Screen的远近平面 远平面: z = 1, 近平面: z = 0, 由此我们可以得到深度变换：[-1, 1] -> [0, 1]

#pragma once

#include <glm/glm.hpp>

class CoordinateUtils {
public:
    CoordinateUtils(const CoordinateUtils&) = delete;
    CoordinateUtils& operator=(const CoordinateUtils&) = delete;

    ~CoordinateUtils() = default;

    static glm::vec3 ndc2Screen(glm::vec3 ndc, const float width, const float height, const bool needDepth);
    static glm::vec3 screen2Ndc(glm::vec3 screen, const float width, const float height, const bool needDepth);

private:
    CoordinateUtils();
};

inline glm::vec3 CoordinateUtils::ndc2Screen(const glm::vec3 ndc, const float width, const float height, const bool needDepth) {
    return needDepth ? glm::vec3((1.f + ndc.x) * 0.5f * width, (1.0f - ndc.y) * 0.5f * height, (1.f + ndc.z) * 0.5f)
    : glm::vec3((1.f + ndc.x) * 0.5f * width, (1.0f - ndc.y) * 0.5f * height, 0.f);
}

inline glm::vec3 CoordinateUtils::screen2Ndc(const glm::vec3 screen, const float width, const float height, const bool needDepth) {
    return needDepth ? glm::vec3((2.0f * screen.x - width) / width, (height - 2.f * screen.y) / height, 2.f * screen.z - 1.0f)
    : glm::vec3(0.f, 0.f, 0.f);
}